﻿using Newtonsoft.Json;
using ra2map_plus.data;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ra2map_plus.service
{
    class Ra2MapPlusService
    {
        public Project Project { get; }

        public string DistData { get; private set; }

        public IniMergeService IniMergeService { get; }

        private readonly AppConfig AppConfig;

        public Ra2MapPlusService(string projectLocation, string rootIniFile, string outputFileName)
        {
            this.IniMergeService = new IniMergeService();
            this.Project = new Project(projectLocation, rootIniFile, outputFileName);
            this.Project.fieldDesc = GlobalDataHolder.DefaultProjectDesc;

            this.AppConfig = GlobalDataHolder.AppConfig;
            this.AppConfig.defaultIncludeIniDirs.ForEach(includeDir =>
            {
                if (Path.IsPathRooted(includeDir))
                {
                    Project.includeIniDirs.Add(includeDir);
                }
                else
                {
                    Project.includeIniDirs.Add(Path.Combine(projectLocation, includeDir));
                }
            });
            this.AppConfig.defaultOutputDirs.ForEach(outputDir =>
            {
                string[] vs = outputDir.Split(GlobalDataHolder.OutputDirAndFileSeparator);
                string realOutputDir = vs[0];

                if (Path.IsPathRooted(realOutputDir))
                {
                    Project.outputDirs.Add(outputDir);
                }
                else
                {
                    string temp = Path.Combine(projectLocation, realOutputDir);
                    if (vs.Length > 1)
                        temp = $"{temp}{GlobalDataHolder.OutputDirAndFileSeparator}{vs[1]}";
                    Project.outputDirs.Add(temp);
                }
            });
            this.loadConfig();
            this.ensureIncludeAndOutputDirs();
        }

        public Ra2MapPlusService(string projectLocation) :
            this(projectLocation, GlobalDataHolder.AppConfig.defaultRootIniFile, GlobalDataHolder.AppConfig.defaultDistFileName) { }

        /// <summary>
        /// 判断输出文件夹是否包含输出文件名
        /// </summary>
        /// <param name="outputDir">输出文件夹</param>
        /// <returns>true：包含文件名</returns>
        private bool isOutputDirContainsFileName(string outputDir)
        {
            return outputDir.Contains(GlobalDataHolder.OutputDirAndFileSeparator);
        }

        /// <summary>
        /// 载入项目配置，覆盖默认的配置
        /// </summary>
        /// <returns></returns>
        private bool loadConfig()
        {
            string configFilePath = Path.Combine(this.Project.location, this.AppConfig.defaultProjectConfigFileName);
            if (File.Exists(configFilePath))
            {
                // 配置文件存在 则读取并覆盖相应属性
                Project project = JsonConvert.DeserializeObject<Project>(File.ReadAllText(configFilePath));
                this.Project.mergeNonNullProperties(project);
            }

            // 写入配置到配置文件
            string v = JsonConvert.SerializeObject(this.Project, Formatting.Indented);
            File.WriteAllText(configFilePath, v);

            return true;
        }

        /// <summary>
        /// 重新加载项目配置
        /// </summary>
        public void ReloadProject()
        {
            this.loadConfig();
            this.ensureIncludeAndOutputDirs();
        }

        /// <summary>
        /// 确保输入与输出文件夹存在(输出不用确保了，输出前会检查)
        /// </summary>
        private void ensureIncludeAndOutputDirs()
        {
            this.Project.includeIniDirs.ForEach(d => Directory.CreateDirectory(d));
        }

        public void MergeIni(bool testMode = false)
        {
            this.Project.includeIniDirs.Sort();
            List<string> mergeList = new List<string>();
            for (int i = 0; i < this.Project.includeIniDirs.Count; i++)
            {
                string includeDir = this.Project.includeIniDirs[i];
                if (Directory.Exists(includeDir))
                {
                    string[] includeIniFiles = Directory.GetFiles(includeDir, "*.ini", SearchOption.TopDirectoryOnly);
                    mergeList.AddRange(includeIniFiles);
                }
            }
            Console.WriteLine(mergeList);
            if (!testMode)
            {
                for (int i = 0; i < mergeList.Count; i++)
                {
                    FileInfo fileInfo = new FileInfo(mergeList[i]);
                    if (fileInfo.Name.Contains("test"))
                    {
                        mergeList.RemoveAt(i--);
                    }
                }
            }
            this.DistData = IniMergeService.Merge(Path.Combine(this.Project.location, this.Project.rootIniFile), mergeList);
        }

        /// <summary>
        /// 将最终生成的地图 ini 写入 dist 文件
        /// </summary>
        /// <returns></returns>
        public bool Write()
        {
            if (DistData == null || DistData.Length == 0)
            {
                return false;
            }
            try
            {
                List<string> outputDirs = this.Project.outputDirs;
                string outputFileName = this.Project.outputFileName;
                foreach (string outputDir in outputDirs)
                {
                    string[] vs = outputDir.Split(GlobalDataHolder.OutputDirAndFileSeparator);
                    string realOutputDir = vs[0];
                    if (vs.Length > 1)
                        outputFileName = vs[1];

                    Directory.CreateDirectory(realOutputDir);
                    File.WriteAllText(Path.Combine(realOutputDir, outputFileName), this.DistData);
                }
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
    }
}
